#ifndef  HELPER_OBJECT_HASH_H
#define  HELPER_OBJECT_HASH_H

#include <utility>
#include <memory>
#include "helper/object/Object.h"
#include "helper/object/Iterator.h"
#include "helper/object/RawType.h"

namespace helper {
namespace object {

class String;
class Array;
/** 
 *  abstract Hash interface
 */
class Hash : public Object{
public:
    typedef std::pair<const std::string, Object *> Pair;

    Hash() :Object(Object::HASH) {}
    ~Hash() override {}

    /**
     * @return the length of Hash
     */
    virtual size_t size() const = 0;

    /**
     * <p> get the reference of Pair with key
     * @return ptr to value type  (Object *) of hash
     */
    virtual const Pair::second_type * get(const Pair::first_type  & key) const = 0;
    /** 
     * contain the key or not
     * @return true if the key is in the hash or false
     */
    virtual bool containsKey(const Pair::first_type & key) const = 0;

    const Pair::second_type * operator[](const Pair::first_type & key) const {
        return get(key);
    }

    virtual std::pair<bool, const char> getChar(const Pair::first_type & key) const = 0;
    virtual std::pair<bool, const int> getInt(const Pair::first_type & key) const = 0;
    virtual std::pair<bool, const long long> getLongLong(const Pair::first_type & key) const = 0;
    virtual std::pair<bool, const double> getDouble(const Pair::first_type & key) const = 0;

    virtual std::pair<bool, std::string> getStdString(const Pair::first_type & key) const = 0;

    virtual String * getString(const Pair::first_type & key) const = 0;
    virtual Array * getArray(const Pair::first_type & key) const = 0;
    virtual Hash * getHash(const Pair::first_type & key) const = 0;



    /**
     * insert the key & value into hash
     * @param key the std::string as Key
     * @param value the Object * as value 
     */
    virtual int insert(const Pair::first_type & key, const Pair::second_type & o) = 0;
    virtual int insert(const Pair::first_type & key, const char ch) = 0;
    virtual int insert(const Pair::first_type & key, const int i) = 0;
    virtual int insert(const Pair::first_type & key, const long long ll) = 0;
    virtual int insert(const Pair::first_type & key, const double dbl) = 0;

    virtual int insert(const Pair::first_type & key, const char * str) = 0;
    virtual int insert(const Pair::first_type & key, const char * buffer , size_t len) = 0;
    virtual int insert(const Pair::first_type & key, const char * buffer , size_t offset, size_t len) = 0;
    virtual int insert(const Pair::first_type & key, size_t n, char ch) = 0;
    /** 
     * insert the key & value into hash
     * @param key the std::string as key
     * @param value the std::string as value
     */
    virtual int insert(const Pair::first_type & key, const std::string & value) = 0;

    virtual std::pair<bool, void *> getPointer(const Pair::first_type & key) const = 0;
    virtual int insertPointer(const Pair::first_type & key, const void * ptr) = 0;

    /**
     * @return the iterator of array,  smart pointer to iterator object, free by myself
     */
    virtual std::shared_ptr<Iterator<Hash::Pair>> iterator() const = 0;

    /** 
     *
     * the memory of old value is managed by user
     * <pre>{@code
     *      Object * old = this.remove("key")
     *      delete old;
     * }</pre>
     *
     *
     * <p> just remove the value (Objet *) in the private container
     * @param key the key of element in hash
     */
    virtual Pair::second_type remove(const Pair::first_type & key) = 0;
    /**
     * <p> set the new value to the hash with key
     * nothing effect to old value 
     *
     *<pre>{@code
     *      Object * new = new Object();
     *      Object * old = this.set("key", new);
     *      if(old != nullptr)
     *          delete old;
     *      else 
     *          delete new;
     *}</pre>
     *
     * @param key the std::string as key
     * @param value the Object *  as value
     */
    virtual Pair::second_type set(const Pair::first_type & key, Pair::second_type & value) = 0;

    virtual void clear() = 0;

    bool operator == (const Hash & right) const{
        return equals(right);
    }
    bool operator != (const Hash & right) const {
        return !(*this == right);
    }
};

} // end of namespace object
} // end of namespace helper

#endif   /* HELPER_OBJECT_HASH_H */
